using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Timers;
using YukiFX5017.Core;

namespace YukiFX5017
{
    public class Npc
    {
        public uint UID;
        public uint Type;
        public string Name;
        public byte Flags;
        public byte Dir;
        public short X;
        public short Y;
        public short Map;
        public uint MaxHP = 900000;
        public uint CurHP = 900000;
        public byte Sob;
        public byte Level;
        public byte Dodge = 25;

        public bool GetDamageDie(uint Damage, Character Attacker)
        {
            if (Damage >= CurHP)
            {
                World.RemoveEntity(this);
                CurHP = MaxHP;
                if (Sob == 2)
                {
                    World.GWOn = false;
                    int Highest = 0;
                    Guild Winner = null;

                    foreach (var DE in Kernel.Chars)
                    {
                        Character Char = DE.Value;
                        if (Char != null)
                        {
                            if (Char.TGTarget != null && Char.TGTarget == this)
                                Char.TGTarget = null;
                        }
                    }

                    Npc Npc = Kernel.Npcs[(uint)6701];
                    if (Npc != null)
                    {
                        if (Npc.Type == 250)
                            Npc.Type -= 10;
                        Npc.CurHP = MaxHP;
                        World.NPCSpawns(Npc);
                    }

                    Npc = Kernel.Npcs[(uint)6702];
                    if (Npc != null)
                    {
                        if (Npc.Type == 250)
                            Npc.Type -= 10;
                        Npc.CurHP = MaxHP;
                        World.NPCSpawns(Npc);
                    }

                    foreach (DictionaryEntry DE in Guilds.AllGuilds)
                    {
                        Guild AGuild = (Guild)DE.Value;
                        AGuild.HoldingPole = false;
                        AGuild.ClaimedPrize = false;
                        if (AGuild.PoleDamaged > Highest)
                        {
                            Highest = AGuild.PoleDamaged;
                            Winner = AGuild;
                        }
                        AGuild.PoleDamaged = 0;
                    }
                    if (Winner != null)
                    {
                        Winner.HoldingPole = true;
                        World.PoleHolder = Winner;
                        World.SendMsgToAll(Winner.GuildName + " has won!", "SYSTEM", 2011);
                    }
                    World.GWScores.Clear();
                    Attacker.TGTarget = null;
                    Attacker.Attacking = false;
                }
                if (Sob == 3 && Type == 240)
                {
                    Type += 10;
                    Attacker.TGTarget = null;
                    Attacker.Attacking = false;
                }                
                
                World.NPCSpawns(this);               
                return true;
            }
            else
            {
                if (Sob == 2 || Sob == 3)
                    if (World.GWOn == false)
                        return false;
                CurHP -= Damage;
                if (Sob == 2)
                {
                    if (Attacker.MyGuild != null)
                    {
                        if (Attacker.MyGuild != World.PoleHolder)
                            Attacker.MyGuild.PoleDamaged += (int)Damage;
                        if (World.GWScores.Contains(Attacker.MyGuild.GuildID))
                            World.GWScores.Remove(Attacker.MyGuild.GuildID);

                        World.GWScores.Add(Attacker.MyGuild.GuildID, Attacker.MyGuild.PoleDamaged);
                    }
                }
                
                return false;
            }
        }
    }

    public class Mobs
    {
        public static void NewRBGuard(short x, short y, short map, uint owner, short glvl)
        {
            try
            {
                uint UID = (uint)General.Rand.Next(400000, 500000);
                while (Kernel.Mobs.ContainsKey(UID))
                {
                    UID = (uint)General.Rand.Next(400000, 500000);
                }
                int gms = 0;
                uint ghp = 0;
                short gat = 0, glv = 0;
                string gna = "";
                if (glvl == 0)
                {
                    ghp = 10000;
                    gat = 300;
                    gna = "IronGuard";
                    gms = 920;
                    glv = 60;
                }
                else if (glvl == 1)
                {
                    ghp = 20000;
                    gat = 600;
                    gna = "CopperGuard";
                    gms = 920;
                    glv = 90;
                }
                else if (glvl == 2)
                {
                    ghp = 34895;
                    gat = 900;
                    gna = "SilverGuard";
                    gms = 920;
                    glv = 110;
                }
                else
                {
                    ghp = 60000;
                    gat = 1300;
                    gna = "GoldGuard";
                    gms = 920;
                    glv = 120;
                }
                //Mob Mob = new Mob(x, y, map, ghp, ghp, 150, gat, UID, gna, gms, glv, (byte)General.Rand.Next(8), 7, owner, false);
                //Kernel.Mobs.Add(UID, Mob);
                //Other.Charowner(owner).Guard = Mob;
                //World.SpawnMobForPlayers(Mob, true);
            }
            catch (Exception Exc) { General.WriteLine(Convert.ToString(Exc)); }
        }
    }
    public class Mob
    {
        public uint ID;
        public short PosX;
        public short PosY;
        public short PrevX;
        public short PrevY;
        public short XStart;
        public short YStart;
        public short Map;
        public uint MaxHP;
        public uint CurHP;
        public short MinAtk;
        public short MaxAtk;
        public uint UID;
        public string Name;
        public int Mech;
        public short Level;
        public byte Pos;
        public bool Alive;
        Character Target = null;
        Mob Target2 = null;
        public uint owner = 0;
        Character owner2 = null;
        public bool frev = true;
        public byte MType = 0;
        
        public int ActionSpeed = 0;
        public int CurrentActionSpeed = 0;

        public bool BossMob = false;
        public byte Dodge = 25;
        DateTime LastAtack;
        DateTime LastTargetting;
        DateTime LastMove;
        public DateTime Death;
        bool Revive = false;

        public void ActionHandle()
        {

            if (MType == 7)
            {
                GetTarget();
            }
            else
            {
                if (DateTime.Now > LastTargetting.AddMilliseconds(2000))
                    GetTarget();
            }
            if (Target != null)
                if (Target.MyClient == null || !Target.MyClient.There || !Target.Alive || !Alive || Target.LocMap != Map)
                    Target = null;

            if (Target != null)
                if (MType != 1 && MType != 4 && MType != 5 && MType != 6)
                    if (Target.Flying)
                        Target = null;

            if (MType == 7)
            {
                if (Target != null)
                    GuardMove(3);
                else if (Target2 != null)
                    GuardMove(2);
                else
                    GuardMove(1);
            }
            else
            {
                if (Target != null)
                    Move();
            }

            if (!Alive)
            {
                if (Revive == false)
                {
                    if (DateTime.Now > Death.AddMilliseconds(3000))
                        Dissappear();
                }
                else
                {
                    if (MType == 2)
                    {
                        if (Map == 1015)
                        {
                            if (DateTime.Now > Death.AddMilliseconds(60000))
                                ReSpawn();
                        }
                        if (Map != 1015)
                        {
                            if (DateTime.Now > Death.AddMilliseconds(600000))
                                ReSpawn();
                        }
                    }
                    if (MType == 0)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();
                    }
                    if (MType == 1)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();
                    }
                    if (MType == 4)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();
                    }
                    if (MType == 3)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();

                    }
                    if (MType == 5)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();
                    }
                    if (MType == 6)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(10000))
                            ReSpawn();
                    }
                    if (MType == 7)
                    {
                        if (DateTime.Now > Death.AddMilliseconds(100))
                            ReSpawn();
                    }
                }
            }
        }
        public void GetTarget()
        {
            LastTargetting = DateTime.Now;
            if (MType != 1 && MType != 7)
                Target = Other.CharNearest((uint)PosX, (uint)PosY, (uint)Map, false);
            else if (MType == 1)
                Target = Other.CharNearest((uint)PosX, (uint)PosY, (uint)Map, true);
            else if (MType == 7)
            {
                if (owner2.MobTarget != null || owner2.PTarget != null)
                {
                    if (owner2.MobTarget != null)
                    {
                        Target2 = owner2.MobTarget;
                        Target = null;
                    }
                    if (owner2.PTarget != null)
                    {
                        Target = owner2.PTarget;
                        Target2 = null;
                    }
                }
                else
                {

                }
            }
        }
        public void GuardMove(short opc)
        {
            if (Alive)
            {
                if (owner2 != null && owner2.Alive && owner2.MyClient.Online && Map == owner2.LocMap)
                {
                    if (DateTime.Now > LastMove.AddMilliseconds(500))
                    {

                        if (MyMath.PointDistance(PosX, PosY, owner2.LocX, owner2.LocY) <= 25)
                        {
                            //Created by Bisiol
                            if (opc == 1)
                            {
                                if ((MyMath.PointDistance(PosX, PosY, owner2.LocX, owner2.LocY) >= 2) && (MyMath.PointDistance(PosX, PosY, owner2.LocX, owner2.LocY) <= 25))
                                {
                                    byte ToDir = (byte)(7 - (Math.Floor(MyMath.PointDirecton(PosX, PosY, owner2.LocX, owner2.LocY) / 45 % 8)) - 1 % 8);


                                    ToDir = (byte)((int)ToDir % 8);
                                    short AddX = 0;
                                    short AddY = 0;
                                    if (ToDir == 255)
                                        ToDir = 7;
                                    Pos = ToDir;

                                    switch (ToDir)
                                    {
                                        case 0:
                                            {
                                                AddY = 1;
                                                break;
                                            }
                                        case 1:
                                            {
                                                AddX = -1;
                                                AddY = 1;
                                                break;
                                            }
                                        case 2:
                                            {
                                                AddX = -1;
                                                break;
                                            }
                                        case 3:
                                            {
                                                AddX = -1;
                                                AddY = -1;
                                                break;
                                            }
                                        case 4:
                                            {
                                                AddY = -1;
                                                break;
                                            }
                                        case 5:
                                            {
                                                AddX = 1;
                                                AddY = -1;
                                                break;
                                            }
                                        case 6:
                                            {
                                                AddX = 1;
                                                break;
                                            }
                                        case 7:
                                            {
                                                AddY = 1;
                                                AddX = 1;
                                                break;
                                            }
                                    }

                                    PrevX = PosX;
                                    PrevY = PosY;
                                    PosX += AddX;
                                    PosY += AddY;
                                    World.MobMoves(this, ToDir);
                                    World.SpawnMobForPlayers(this, true);
                                    PrevX = PosX;
                                    PrevY = PosY;
                                    PosX += AddX;
                                    PosY += AddY;
                                    World.MobMoves(this, ToDir);
                                    World.SpawnMobForPlayers(this, true);


                                }
                                else if (MyMath.PointDistance(PosX, PosY, owner2.LocX, owner2.LocY) < 2)
                                { }
                            }
                            else if (opc == 2)
                            {

                                if (DateTime.Now > LastAtack.AddMilliseconds(1000))
                                {
                                    if (MyMath.PointDistance(PosX, PosY, Target2.PosX, Target2.PosY) <= 10)
                                    {
                                        LastMove = DateTime.Now;

                                        int DMG = Convert.ToInt32(MaxAtk);

                                        if (DMG < 1)
                                            DMG = 1;


                                        uint GEXP = 0;
                                        if (DMG <= Target2.CurHP)
                                            GEXP = (uint)DMG;
                                        else if (DMG > Target2.CurHP)
                                            GEXP = Target2.CurHP;
                                        Target2.GetDamage((uint)DMG, owner2);
                                        if (Target2.MType != 1 && Target2.MType != 7)
                                        { owner2.AddExp(GEXP, true); }
                                        foreach (var DE in Kernel.Chars)
                                        {
                                            Character Charr = DE.Value;

                                            if (Charr.MyClient.Online)
                                                if (MyMath.CanSeeBig(PosX, PosY, Charr.LocX, Charr.LocY))
                                                {
                                                    Charr.MyClient.Send(General.MyPackets.MobSkillUse2(this, Target2, (uint)DMG, 1002, 1));
                                                }
                                        }
                                        if (Target2.CurHP <= 0)
                                            Target2 = null;
                                        LastAtack = DateTime.Now;
                                    }
                                    else if ((MyMath.PointDistance(PosX, PosY, Target2.PosX, Target2.PosY) >= 11) && (MyMath.PointDistance(PosX, PosY, Target2.PosX, Target2.PosY) <= 25))
                                    {
                                        byte ToDir = (byte)(7 - (Math.Floor(MyMath.PointDirecton(PosX, PosY, Target2.PosX, Target2.PosY) / 45 % 8)) - 1 % 8);



                                        ToDir = (byte)((int)ToDir % 8);
                                        short AddX = 0;
                                        short AddY = 0;
                                        if (ToDir == 255)
                                            ToDir = 7;
                                        Pos = ToDir;

                                        switch (ToDir)
                                        {
                                            case 0:
                                                {
                                                    AddY = 1;
                                                    break;
                                                }
                                            case 1:
                                                {
                                                    AddX = -1;
                                                    AddY = 1;
                                                    break;
                                                }
                                            case 2:
                                                {
                                                    AddX = -1;
                                                    break;
                                                }
                                            case 3:
                                                {
                                                    AddX = -1;
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 4:
                                                {
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 5:
                                                {
                                                    AddX = 1;
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 6:
                                                {
                                                    AddX = 1;
                                                    break;
                                                }
                                            case 7:
                                                {
                                                    AddY = 1;
                                                    AddX = 1;
                                                    break;
                                                }
                                        }

                                        PrevX = PosX;
                                        PrevY = PosY;
                                        PosX += AddX;
                                        PosY += AddY;
                                        World.MobMoves(this, ToDir);
                                        World.SpawnMobForPlayers(this, true);
                                        PrevX = PosX;
                                        PrevY = PosY;
                                        PosX += AddX;
                                        PosY += AddY;
                                        World.MobMoves(this, ToDir);
                                        World.SpawnMobForPlayers(this, true);


                                    }


                                }
                            }
                            else if (opc == 3)
                            {

                                if (DateTime.Now > LastAtack.AddMilliseconds(1000))
                                {
                                    if (MyMath.PointDistance(PosX, PosY, Target.LocX, Target.LocY) <= 10)
                                    {
                                        int DMG = MaxAtk - (int)Target.MDefense;
                                        if (DMG < 1)
                                            DMG = 1;

                                        if (Target.GetHitDie((uint)DMG))
                                        {
                                            if (MType == 7)
                                            {
                                                World.MobAttacksCharSkill(this, Target, (uint)DMG, 1002, 1);

                                            }

                                        }
                                        else
                                        {
                                            if (MType == 7)
                                                World.MobAttacksCharSkill(this, Target, (uint)DMG, 1002, 1);
                                        }
                                        if (Target.CurHP <= 0)
                                            Target = null;
                                        LastAtack = DateTime.Now;
                                    }
                                    else if ((MyMath.PointDistance(PosX, PosY, Target.LocX, Target.LocY) >= 11) && (MyMath.PointDistance(PosX, PosY, Target.LocX, Target.LocY) <= 25))
                                    {
                                        byte ToDir = (byte)(7 - (Math.Floor(MyMath.PointDirecton(PosX, PosY, Target.LocX, Target.LocY) / 45 % 8)) - 1 % 8);



                                        ToDir = (byte)((int)ToDir % 8);
                                        short AddX = 0;
                                        short AddY = 0;
                                        if (ToDir == 255)
                                            ToDir = 7;
                                        Pos = ToDir;

                                        switch (ToDir)
                                        {
                                            case 0:
                                                {
                                                    AddY = 1;
                                                    break;
                                                }
                                            case 1:
                                                {
                                                    AddX = -1;
                                                    AddY = 1;
                                                    break;
                                                }
                                            case 2:
                                                {
                                                    AddX = -1;
                                                    break;
                                                }
                                            case 3:
                                                {
                                                    AddX = -1;
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 4:
                                                {
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 5:
                                                {
                                                    AddX = 1;
                                                    AddY = -1;
                                                    break;
                                                }
                                            case 6:
                                                {
                                                    AddX = 1;
                                                    break;
                                                }
                                            case 7:
                                                {
                                                    AddY = 1;
                                                    AddX = 1;
                                                    break;
                                                }
                                        }

                                        PrevX = PosX;
                                        PrevY = PosY;
                                        PosX += AddX;
                                        PosY += AddY;
                                        World.MobMoves(this, ToDir);
                                        World.SpawnMobForPlayers(this, true);
                                        PrevX = PosX;
                                        PrevY = PosY;
                                        PosX += AddX;
                                        PosY += AddY;
                                        World.MobMoves(this, ToDir);
                                        World.SpawnMobForPlayers(this, true);


                                    }


                                }
                            }

                        }
                        else
                        {
                            Gjump();
                            World.SpawnMobForPlayers(this, true);
                            Target = null;
                            Target2 = null;
                        }

                        LastMove = DateTime.Now;
                    }
                }
                else
                    Dissappear();
            }
        }
        public void Move()
        {
            LastMove = DateTime.Now;
            byte MinRange = 0;
            byte MaxRange = 0;

            if (MType == 0)
            {
                MinRange = 2;
                MaxRange = 20;
            }
            else if (MType == 1)
            {
                MinRange = 15;
                MaxRange = 20;
            }
            else if (MType == 2)
            {
                MinRange = 4;
                MaxRange = 30;
            }


            if (MyMath.PointDistance(PosX, PosY, Target.LocX, Target.LocY) <= MaxRange && MyMath.PointDistance(Target.LocX, Target.LocY, PosX, PosY) >= MinRange)
            {
                if (Other.ChanceSuccess(80) || BossMob)
                {
                    byte ToDir = (byte)(7 - (Math.Floor(MyMath.PointDirecton(PosX, PosY, Target.LocX, Target.LocY) / 45 % 8)) - 1 % 8);

                    if (!Other.PlaceFree(PosX, PosY, ToDir, (ushort)Map))
                        return;

                    ToDir = (byte)((int)ToDir % 8);
                    short AddX = 0;
                    short AddY = 0;
                    if (ToDir == 255)
                        ToDir = 7;
                    Pos = ToDir;

                    switch (ToDir)
                    {
                        case 0:
                            {
                                AddY = 1;
                                break;
                            }
                        case 1:
                            {
                                AddX = -1;
                                AddY = 1;
                                break;
                            }
                        case 2:
                            {
                                AddX = -1;
                                break;
                            }
                        case 3:
                            {
                                AddX = -1;
                                AddY = -1;
                                break;
                            }
                        case 4:
                            {
                                AddY = -1;
                                break;
                            }
                        case 5:
                            {
                                AddX = 1;
                                AddY = -1;
                                break;
                            }
                        case 6:
                            {
                                AddX = 1;
                                break;
                            }
                        case 7:
                            {
                                AddY = 1;
                                AddX = 1;
                                break;
                            }
                    }

                    PrevX = PosX;
                    PrevY = PosY;
                    PosX += AddX;
                    PosY += AddY;
                    World.MobMoves(this, ToDir);
                    World.SpawnMobForPlayers(this, true);

                }
            }
            else if (MyMath.PointDistance(PosX, PosY, Target.LocX, Target.LocY) <= MinRange)
                if (Target.Alive)
                {
                    if (Other.ChanceSuccess(50) || BossMob && Other.ChanceSuccess(85) || MType == 1)
                    {
                        int DMG = General.Rand.Next(MinAtk, MaxAtk) - (int)Target.Defense;

                        if (DMG < 1)
                            DMG = 1;

                        if (Target.GetHitDie((uint)DMG))
                        {
                            if (MType == 1)
                                World.MobAttacksCharSkill(this, Target, (uint)DMG, 1320, 2);
                            else
                                World.MobAttacksChar(this, Target, 2, (uint)DMG);
                            World.MobAttacksChar(this, Target, 14, (uint)DMG);
                        }
                        else
                        {
                            if (MType == 1)
                                World.MobAttacksCharSkill(this, Target, (uint)DMG, 1320, 2);
                            else
                                World.MobAttacksChar(this, Target, 2, (uint)DMG);
                        }
                        Target = null;
                    }
                }
                else
                {
                    Target = null;
                }

        }        
        public bool GetDamage(uint Damage, Character Attacker)
        {
            if (CurHP > Damage)
            {
                CurHP -= Damage;

                return false;
            }
            else
            {                
                CurHP = 0;
                Alive = false;
                Revive = false;

                MonsterDrops.MonsterDrop(this, Attacker);

                return true;
            }
        }

        public void Dissappear()
        {
            if (MType == 7 && frev == false)
            {
                World.RemoveEntity(this);
                Kernel.Mobs.Remove(this.UID);
                Alive = false;
            }
            else if (MType == 7 && frev == true)
            {
                World.RemoveEntity(this);
                Revive = true;
                frev = false;
            }
            else
            {
                World.RemoveEntity(this);
                Revive = true;
            }
        }
        public void ReSpawn()
        {
            CurHP = MaxHP;
            Alive = true;
            PosX = XStart;
            PosY = YStart;
            PrevX = PosX;
            PrevY = PosY;
            World.MobReSpawn(this);
            Revive = false;
        }
        public void Gjump()
        {
            PosX = (short)owner2.LocX;
            PosY = (short)owner2.LocY;
            PrevX = PosX;
            PrevY = PosY;
            World.GuardReSpawn(this);

        }
    }
}
